package com.arrogames.blondbattle.game.combat 
{
	import ash.core.Engine;
	import ash.core.NodeList;
	import ash.tools.ListIteratingSystem;
	import com.arrogames.blondbattle.game.combat.Faction;
	import com.arrogames.blondbattle.game.movement.Dimension;
	import com.arrogames.blondbattle.game.movement.Position;
	import com.arrogames.blondbattle.game.combat.Target;
	import com.arrogames.blondbattle.game.combat.TargetNode;
	import com.arrogames.blondbattle.game.combat.TargetingNode;
	
	import org.as3commons.logging.api.ILogger;
	import org.as3commons.logging.api.getLogger;
	
	
	/**
	 * ...
	 * @author ...
	 */
	public class TargetingSystem extends ListIteratingSystem 
	{
		
		private static const logger:ILogger = getLogger(TargetingSystem);
		
		private var targetNodes:NodeList;
		
		public function TargetingSystem() {
			super(TargetingNode, updateNode);
		}
		
		override public function addToEngine(engine:Engine):void {
			super.addToEngine(engine);
			
			targetNodes = engine.getNodeList(TargetNode);
			targetNodes.nodeRemoved.add(targetNodeRemoved);
		}
		
		override public function removeFromEngine(engine:Engine):void {
			super.removeFromEngine(engine);
			
			targetNodes = null;
		}
		
		/**
		 * Update the node
		 * 
		 * @param	currentNode	the node looking for targets
		 * @param	time		change in time, not used in this context
		 */
		private function updateNode( currentNode:TargetingNode, time:Number ) : void {
			//current nodes position and 
			var position:Position = currentNode.position;
			var faction:Faction = currentNode.faction;
			var range:Number = currentNode.weapon.range.value;
			var myDimension:Dimension = currentNode.dimension;
			var targetPosition:Position = null;
			var targetDimension:Dimension = null;
			
			//check if the current target is still within range
			var currentTarget:Target = currentNode.entity.get(Target);
			if ( currentTarget != null && !targetWithinRange(position, currentTarget.node.position, myDimension, currentTarget.node.dimension, range)) {
				logger.debug("currenttarget: " + currentTarget.node.position);
				logger.debug("unit " + currentNode.entity.name + " has lost its target");
				currentTarget = null;
				currentNode.entity.remove(Target);
			}
			
			//only check for a new target if the current node does not have one already
			if (null == currentTarget) {
				//check the list of available targetnodes
				var targetNode : TargetNode
				for( targetNode = targetNodes.head; targetNode; targetNode = targetNode.next ) {
					//check if we are allowed to target
					if ( targetNode.faction.name != faction.name) {
						targetPosition = targetNode.position;
						targetDimension = targetNode.dimension;
						if( targetWithinRange (position, targetPosition, myDimension, targetDimension, range) ) {
							logger.debug("unit " + currentNode.entity.name + " has found target: " + targetNode.entity.name);
							//we have a target!
							var target:Target = new Target(targetNode);
							currentNode.entity.add(target);
							//break out of the loop as we have found a target
							break;
						}
					}
				}
			
			}
		}
		
		/**
		 * Check if the given target position is within range
		 * 
		 * @param	myPosition		Point
		 * @param	targetPosition	Point
		 * @return	Boolean
		 */
		private function targetWithinRange(myPosition:Position, targetPosition:Position, myDimension:Dimension, targetDimension:Dimension, range:Number) : Boolean
		{
			var diffX:Number = targetPosition.position.x - myPosition.position.x;
			var diffY:Number = targetPosition.position.y + targetDimension.height/2 - myPosition.position.y + myDimension.height/2;
			
			var withinRange:Boolean = false;
			//check if the diffX and diffY result in a range short enough to fire at
			var targetRange:Number = Math.sqrt( Math.pow(diffX, 2) + Math.pow(diffY, 2));
			if ( range >= targetRange  ) {
				withinRange = true;
			}
			return withinRange;
		}
		
		
		
		private function targetNodeRemoved(node:TargetNode) : void
		{
			var targetNode : TargetingNode;
			for ( targetNode = super.nodeList.head; targetNode; targetNode = targetNode.next ) {
				var target:Target = targetNode.entity.get(Target);
				if ( null != target && target.node.entity == node.entity ) {
					logger.debug('removing target ('+ node.entity.name + ') from: ' + targetNode.entity.name);
					targetNode.entity.remove(Target);
				}
			}
		}
	}

}